/* client.cc:  */

#include "connection.h"
#include "connectionclosedexception.h"
#include "protocol.h"
#include "messagehandler.h"


#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>    /* for exit() and atoi() */

using namespace std;
using namespace client_server;

/*
 * Outputs the intro text.
 */
void introText(){
    cout << "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤" << endl;
    cout << "¤¤¤¤¤¤¤¤ Hi and welcome to our NewsServer ¤¤¤¤¤¤¤¤¤¤¤" << endl;
    cout << "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤" << endl;
    cout << "Available commands are: L_NG, List newsgroup"<< endl;
    cout << "                        C_NG name, Create newsgroup"<< endl;
    cout << "		        D_NG newsgroupid, Delete newsgroup"<< endl;
    cout << "		        L_A newsgroupid, List articles"<< endl;
    cout << "		        C_A newsgroupid, Create article"<< endl;
    cout << "		        D_A newsgroupid articleId "<< endl;
    cout << "		        G_A newsgroupid articleId, Get article"<< endl;
    cout << "" << endl;
    cout << "Please type your command: ";
}

/*
 * Sends a command over the connection.
 */
void sendCommand(int command, Connection& conn)
{
	conn.write(command);
}

/*
 * Encodes an int-value into four bytes and sends it over the connection with the most significant byte first.
 */
void sendInt(int send, Connection& conn)
{
	conn.write((send>>24)&0xFF);
	conn.write((send>>16)&0xFF);
	conn.write((send>>8)&0xFF);
	conn.write((send>>0)&0xFF);
}

/*
 * Encodes and sends a NUM_P over the connection.
 */
void sendNumP(int send, Connection& conn)
{
	sendCommand(protocol::Protocol::PAR_NUM, conn);
	sendInt(send, conn);
}

/*
 * Encodes and sends a STRING_P over the connection.
 */
void sendStringP(string send, Connection& conn)
{
	sendCommand(protocol::Protocol::PAR_STRING, conn);
	sendInt(send.size(), conn);
	for(size_t i = 0; i < send.size(); i++) {
		conn.write(send.at(i));
	}	
}


int main(int argc, char* argv[]) {
    if (argc != 3) {
        cerr << "Usage: myclient host-name port-number" << endl;
        exit(1);
    }
    
    Connection conn(argv[1], atoi(argv[2]));
    if (!  conn.isConnected()) {
        cerr << "Connection attempt failed" << endl;
        exit(1);
    }
    introText();
    string command;
    while (cin >> command) {
	  
	if(command.compare("L_NG") == 0){ //LIST_NEWSGROUPS:
		sendCommand(protocol::Protocol::COM_LIST_NG, conn);
		sendCommand(protocol::Protocol::COM_END, conn);
	}else if(command.compare("C_NG") == 0){ //CREATE_NEWSGROUP: parameter name
		sendCommand(protocol::Protocol::COM_CREATE_NG, conn);
		string groupName;
		cin.ignore(1);
		getline(cin, groupName);
		sendStringP(groupName, conn);
		sendCommand(protocol::Protocol::COM_END, conn);
	}else if(command.compare("D_NG") == 0){ //DELETE_NEWSGROUP: parameter newsgroupId
		sendCommand(protocol::Protocol::COM_DELETE_NG,conn);
		int groupId;
		cin >> groupId;
		sendNumP(groupId,conn);
		sendCommand(protocol::Protocol::COM_END, conn);
	}else if(command.compare("L_A") == 0){ //LIST_ARTICLES: parameter newsgroupId
		sendCommand(protocol::Protocol::COM_LIST_ART, conn);
		int groupId;
		cin >> groupId;
		sendNumP(groupId, conn);
		sendCommand(protocol::Protocol::COM_END,conn);
	}else if(command.compare("C_A") == 0){ //CREATE_ARTICLE: parameter newsgroupID, articleName, authorName, text
		sendCommand(protocol::Protocol::COM_CREATE_ART, conn);
		int groupId;
		cin >> groupId;
		sendNumP(groupId, conn);
		string artName;
		cout << "Enter article name:" << endl;
		cin.ignore(1);
		getline(cin, artName);
		sendStringP(artName, conn);
		string authorName;
		cout << "Enter author name:" << endl;
		cin.ignore(1);
		getline(cin, authorName);
		sendStringP(authorName, conn);
		cout << "Enter content of article:" << endl;
		cin.ignore(1);
		string txt = "";
		string sendeh = "";
		getline(cin, txt);
		while(txt != "."){
			sendeh += txt;
			sendeh += "\n";
			getline(cin, txt);
		}
		sendStringP(sendeh, conn);
		sendCommand(protocol::Protocol::COM_END, conn);
	}else if(command.compare("D_A") == 0){ //DELETE_ARTICLE: parameter newsgroupId articleId
		sendCommand(protocol::Protocol::COM_DELETE_ART,conn);
		int groupId;
		cin >> groupId;
		sendNumP(groupId,conn);
		int artId;
		cin >> artId;
		sendNumP(artId,conn);
		sendCommand(protocol::Protocol::COM_END, conn);
	}else if(command.compare("G_A") == 0){//GET_ARTICLE: parameter newsgroupID, articleId
		sendCommand(protocol::Protocol::COM_GET_ART, conn);
		int groupId;
		cin >> groupId;
		sendNumP(groupId, conn);
		int artId;
		cin >> artId;
		sendNumP(artId, conn);
		sendCommand(protocol::Protocol::COM_END,conn);
	}else{
		cout << "Wrong input, connection killed ^_^" << endl;
		cout << "Available commands are L_NG, C_NG, D_NG, L_A, D_A, C_A" << endl;
		exit(1);
	}

	try {	//Läser från servern
		MessageHandler mh(conn);
		char command = mh.getCommand();
		if (command == protocol::Protocol::ANS_LIST_NG){
			char* response = mh.getParameters();
			int nbrOfGroups = MessageHandler::readInt(response);
           		cout << "The number of newsgroups are: " << nbrOfGroups << endl;
           		cout << "GroupId:        Name: " << endl;
           		for(int i = 0; i < nbrOfGroups; i++){
           			int groupId = MessageHandler::readInt(response);
           			string name = MessageHandler::readString(response);
           			cout << groupId << "               " << name << endl;
           			}
		}else if(command == protocol::Protocol::ANS_CREATE_NG){
			char* response = mh.getParameters();			
			if(*response == protocol::Protocol::ANS_ACK){
				cout << "Newsgroup successfully created" << endl;
			}else if(*response == protocol::Protocol::ANS_NAK){
				cout << "Newsgroup already exist" << endl;
			}else {
				cout << "wrong respons" << *response << endl;
			}
		}else if(command == protocol::Protocol::ANS_DELETE_NG){
			char* response = mh.getParameters();
			if(*response == protocol::Protocol::ANS_ACK){
				
				cout << "Newsgroup successfully deleted: " << endl;
			}else{
				cout << "Newsgroup does not exist" << endl;
			}
		}else if(command == protocol::Protocol::ANS_LIST_ART){
			char* response = mh.getParameters();
			if(*response == protocol::Protocol::ANS_ACK){
				response++;
				int nbrOfArticles = MessageHandler::readInt(response);
				cout <<"The number of articles are: " << nbrOfArticles << endl;
				cout << "ArticleId:            Name: " << endl;
				for(int i = 0; i < nbrOfArticles; i++){
           				int articleId = MessageHandler::readInt(response);
           				string name = MessageHandler::readString(response);
           			cout << articleId << "                     " << name << endl;
           			}
			
			}else{
				cout << "Newsgroup does not exist" << endl;
			}
		}else if(command == protocol::Protocol::ANS_CREATE_ART){
			char* response = mh.getParameters();
			if(*response == protocol::Protocol::ANS_ACK){
				cout << "Article successfully created" << endl;			
			}else{
				cout << "Article does not exist" << endl;
			}
		}else if(command == protocol::Protocol::ANS_DELETE_ART){
			char* response = mh.getParameters();
			if(*response == protocol::Protocol::ANS_ACK){
				cout << "Article successfully deleted" << endl;			
			}else{
				cout << "Newsgroup does not exist" << endl;
			}
		}else if(command == protocol::Protocol::ANS_GET_ART){
			char* response = mh.getParameters();
			if(*response == protocol::Protocol::ANS_ACK){
				response++;
				string title = MessageHandler::readString(response);
				string author = MessageHandler::readString(response);
				string content = MessageHandler::readString(response);
				cout << "Title: " << title << endl;
				cout << "Author: " << author << endl;
				cout << "" << endl;
				cout << content << endl;
						
			}else{	
				response++;
				if(*response == protocol::Protocol::ERR_NG_DOES_NOT_EXIST){
					cout << "Newsgroup does not exist" << endl;
				}else{
					cout << "Article does not exist" << endl;
				}
			
			}
		}
		cout << "Type another command: ";
	}catch (ConnectionClosedException&) {
            cerr << "Server closed down!" << endl;
            exit(1);
        }

    }
}



